Los gráficos e infografías son, cada vez más, una parte importante de la mayoría de textos escritos, ya sea este un informe técnico, un artículo de periódico o un TFG. En el caso de la ciencia de datos, como puede verse abajo en la infografía del fantástico manual R for Data Science, el análisis y la exploración de los datos es un proceso iterativo en el que la visualización y la generación de gráficos ocupa un lugar destacado.
Uno de los instrumentos y tareas fundamentales de un científico de datos es la capacidad de realizar visualizaciones de datos apropiadas y convincentes. El análisis gráfico no solo ayuda en la exploración y comprensión de los datos, sino que es fundamental a la hora de mostrar las posibles relaciones entre variables, descubrir relaciones o patrones ocultos, y descartar o sugerir nuevas preguntas sobre los datos.
El entorno R tiene diversos sistemas para visualizar datos, los 2 más utilizados son el sistema gráfico de R-base y el ecosistema asociado al paquete ggplot2. Por diversas razones, en el curso usaremos el entorno ggplot2 para hacer nuestros gráficos; de hecho, en la actualidad ggplot2, dada su rapidez en la iteración entre gráficos, versatilidad y la cuidada estética que tienen sus gráficos, se ha convertido, al menos por el momento, en el sistema estándar para hacer gráficos en R. Por ejemplo, ¿cómo creeis que hace la BBC sus gráficos?, evidentemente con R y ggplot. Puedes ver uno de sus repositorios aquí
Con ggplot2 es sencillo hacer gráficos con calidad para ser publicados o mostrados, además de que, dada su sintaxis modular, hace sencillo el reutilizar los gráficos durante el proceso de análisis. El paquete ggplot2 fue inicialmente desarrollado por Hadley Wickham, pero actualmente el ecosistema ggplot es el resultado de toda una comunidad de usuarios que contribuye a enriquecer el sistema gráfico con sus extensiones y paquetes auxiliares.
En palabras de Hadley en su libro sobre ggplot2:
ggplot2 is an R package for producing statistical, or data, graphics, but it is unlike most other graphics packages because it has a deep underlying grammar. This grammar, based on the Grammar of Graphics (Wilkinson 2005), is made up of a set of independent components that can be composed in many different ways. This makes ggplot2 very powerful because you are not limited to a set of pre-specified graphics, but you can create new graphics that are precisely tailored for your problem. This may sound overwhelming, but because there is a simple set of core principles and very few special cases, ggplot2 is also easy to learn (although it may take a little time to forget your preconceptions from other graphics tools).
Sí, con ggplot2 es “fácil” hacer rápidamente gráficos de calidad, PERO dominar todos los detalles del paquete sí que es complicado, pero no nos hace falta conocerlo todo; además ggplot2 es un paquete/entorno en constante evolución. Actualmente está en la versión 3.2.1.
Para entender esto de la constante evolución y el papel que tiene la comunidad de usuarios en el desarrollo de R y sus paquetes puedes leer este tweet y las respuestas a él. Interviene una persona de la BBC. En el tweet sólo se anuncia una pequeña mejora en como ggplot2 gestiona los títulos de los gráficos, donde habitualmente se produce la discusión/colaboración entre usuarios para implementar mejoras en el repo de la versión de desarrollo del paquete. Puedes ver como se gestó está pequeña mejora aquí. Fue la issue 3252 de ggplot2. justo cuando estaba escribiendo esto leí este tweet con una mejora implementada en ggplot2
La pagina web de ggplot2 puedes encontrarla aquí, donde puedes encontrar documentos de ayuda y la referencia oficial. Para darte cuenta de todo lo que se puede hacer con el ecosistema ggplot, visita esta página donde podrá ver los 58 “paquetes auxiliares” o extensiones a ggplot2.
Para hacer “buenos” gráficos con ggplot2no sólo es necesario entender la sintaxis y los pormenores del paquete, para eso aquí tenemos la ayuda oficial de ggplot2, sino que quizás se necesite algo más. Por ejemplo, algo de experiencia y cierta capacidad visual y estética; incluso hay quien dice que hacer buenos gráficos es un arte, para intentar mejorar vuestros gráficos o darse cuenta de ciertos errores,aquí tenéis algunas reglas/consejos, y aquí un curso completo, en R, sobre visualización, con bookdown incluido..Otro libro sobre visualización con los ejemplos con ggplot2 aquí. Otro libro más: Fundamentals of Data VizAlgunos consejos de la BBC
Ya se dijo que ggplot2 es un paquete R desarrollado por Hadley Wickham, aunque actualmente es el resultado de la colaboración de múltiples desarrolladores. ggplot2 implementa en R “The Grammar of Graphics” de Wilkinson, un sistema coherente para describir y construir gráficos. El énfasis de ggplot2 está en la exploración rápida de datos, especialmente de datos de alta dimensionalidad. Con ggplot2 es sencillo ir transformando el gráfico mientras se van analizando los datos.
Para empezar a entender la “filosofía” de ggplot2 os planteo una pregunta medio retórica: ¿qué vemos en el gráfico de abajo?
Pues sí, es un gráfico de puntos y nos ayuda a ver las relaciones que existen entre 3 variables. Estamos habituados a ello, pero vamos a pensar en el gráfico desde la óptica de “The Grammar of Graphics” implementada en el paquete ggplot2.
En nuestro gráfico se representan por medio de puntos, en el espacio X-Y, y mediante los distintos colores de los puntos, las observaciones de 3 variables. Bien, nada muy novedoso, todos los sistemas gráficos hacen este tipo de gráficos. Los gráficos de ggplot2 se realizan mediante la superposición de elementos/capas. Podemos pensar que el gráfico que hemos visto es una capa. ¿Cómo creamos este gráfico o capa en ggplot2?
Pues, una de las principales ideas para entender ggplot2 es que cada capa de un gráfico tiene 3 componentes o elementos principales:
los datos que se van a representar (sencillo, para hacer un gráfico hacen falta datos). Para ello utilizaremos generalmente la función ggplot()
un conjunto de propiedades estéticas asociadas o mapeadas a alguna variable del conjunto de datos. Por ejemplo, la variable Sepal.Lenght está asociada al eje X. Por su parte, el color de los puntos (otra característica visual o estética) está asociado a los valores de la variable Species. Es decir, usando la terminología de ggplot2, las distintas variables están asociadas o mapeadas a determinadas características estéticas. El mapeo de variables con estéticas se hará con la función aes() de aesthetics. (esto ya no es tan estándar, se explica en breve)
el elemento geométrico que se va a representar. En nuestro caso el elemento geométrico que se utiliza para representar los valores de las variables son los puntos, pero podrían haber sido las lineas o las barras … Para especificar el elemento geométrico que vamos a usar en nuestro gráfico se utiliza la familia de funciones geom_xx(); por ejemplo geom_point() si queremos puntos, geom_line() si queremos que las relaciones entre las variables se representen/visualicen como lineas.
Así en abstracto puede ser complicado entender del todo que quiere decir todo esto. Vamos a verlo con ejemplos concretos. De momento, para explicar las principales características de ggplot2 utilizaré un conjunto de datos famoso, pero odiado por algunos, por haber sido utilizado en numerosos ejemplos y cursos: el iris dataset.
El conjunto de datos iris contiene datos sobre 150 flores, en concreto sobre 150 lirios. iris tiene 5 variables, 4 de ellas miden la longitud y el ancho del pétalo y del sépalo de los 150 lirios. Estas 4 primeras variables son cuantitativas y continuas; mientras que la quinta variable es categórica, indicando la clase o variedad de los lirios, ya que en los datos hay 3 especies distintas de lirios (setosa, versicolor y virginica). Con estos datos, con 3 de sus variables, se ha creado el gráfico que ves más arriba.
PRIMER GRÁFICO: Para comenzar nuestras andanzas con ggplot2 intentaremos replicar el gráfico de arriba; aunque primero utilizaremos sólo 2 variables; es decir, haremos un gráfico de puntos de la longitud del sépalo frente a la longitud del pétalo.
Hacer un gráfico con ggplot2 requiere de varias etapas,
la primera de ellas consiste en usar la función ggplot() para inicializar el gráfico.
en segundo lugar, tendremos que especificar que conjunto de datos usaremos en el gráfico.
en tercer lugar tendremos que especificar que variables irán asociadas a determinados elementos visuales o estéticos del gráfico
por último, en cuarto lugar, tendremos que especificar que tipo de gráfico o geometría usaremos para visualizar las observaciones.
Veámoslo más detenidamente.
En ggplot2, para hacer un gráfico se empieza SIEMPRE llamando a la función ggplot(). Si tecleamos ggplot() en la consola o en un script, parece que no ocurre nada, pero tras la llamada a la función ggplot(), R ha creado un objeto, un contenedor para nuestro futuro gráfico. Aún no vemos el gráfico, faltan cosas, pero ya lo hemos inicializado. Si quieres ver el objeto/contenedor que hemos creado con la llamada a ggplot() tienes que asignarle un nombre, así podrás verlo en la pestaña “Environment” de RStudio.
Para verlo tienes que hacer:
my_grafico <- ggplot()
my_grafico, es un objeto R, concretamente una lista con 9 elementos, que tendremos que ir “llenando” para hacer nuestro gráfico.
Generalmente, dentro de la función ggplot() se suele especificar el conjunto de datos que vas a utilizar para hacer el gráfico. A diferencia de los gráficos de R-base, ggplot2 no permite graficar vectores: los datos que se suministran han de ser SIEMPRE data.frames o similares.
ggplot(data = iris)
ggplot(iris)
Ya está, con cualquiera de las 2 instrucciones de arriba, son equivalentes1, ya hemos inicializado el gráfico y le hemos dicho que datos vamos a usar.
Dijimos que para comenzar haríamos un gráfico de puntos de la variable Sepal.Length frente a Petal.Length; así que tenemos que decirle a ggplot2 que variables de iris queremos visualizar y con que propiedades estéticas queremos asociar cada variable. Para ello utilizaremos la función aes() dentro de ggplot(). Lo hacemos con la siguiente expresión:
ggplot(iris, aes(x = Sepal.Length, y = Petal.Length))
Aún no vemos el gráfico, pero con aes() le hemos dicho a R/ggplot2 que queremos asociar/mapear la variable Sepal.Length al eje x, y la variable Petal.Length al eje y. Fíjate que, en la pestaña de gráficos de RStudio, ya vemos los ejes del gráfico; además, fíjate que ggplot2 ya ha calculado para nosotros el rango de las variables para ajustar los ejes.
Al igual que antes, podemos omitir los nombres de las opciones de la función aes(). Esta función puede tener muchos argumentos (veremos algunos), pero los 2 primeros son siempre x (el eje x) y después y (el eje y o vertical de mi gráfico); es decir podríamos hacer lo siguiente que es más rápido de teclear.
ggplot(iris, aes(Sepal.Length, Petal.Length))
Con esta instrucción le estamos diciendo a ggplot2 que vamos a hacer un gráfico con los datos del data.frame iris y que vamos a asociar/conectar/mapear la variable Sepal.Length con el eje x, y la variable Petal.Length con el eje y del gráfico. Perfecto, pero entonces ¿por qué no vemos el gráfico? La razón estriba en que no le hemos dicho a ggplot2 qué tipo de gráfico queremos (de puntos, de lineas etc…). El tipo de gráfico se explicita con una familia de funciones: geom_xx() o geometrías. Hay muchas geometrías o tipos de gráficos que podemos usar. Ya lo veremos!!! Nosotros queremos hacer un gráfico de puntos, así que, de la familia de geometrías tenemos que usar geom_point(). Veámoslo.
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point()
Como vemos los puntos del gráfico se visualizan en color negro, con un tamaño, una transparencia y una forma determinadas. Obviamente todo esto se puede cambiar dentro de geom_point() con las opciones adecuadas. Por ejemplo:
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point(color = "red", size = 2, alpha = 0.2)
Ya casi está. No es tan complicado. Ya hemos visto las ideas fundamentales de la visualización con ggplot2:
Los gráficos se inician con la función ggplot(). Generalmente aquí se especifican los datos (data.frame) que queremos utilizar
La función aes() sirve para asociar/mappear variables con atributos/características estéticas del gráfico. De hecho el nombre del función aes() viene de aesthetics. Las aesthetics más importantes de un gráfico suelen ser los ejes x e y, por eso se ponen siempre al principio de aes(); es decir, son los 2 primeros argumentos de aes(). En nuestro ejemplo hemos asociado la variable Sepal.Length con el eje x, y la variable Petal.Length con el eje y. Veremos más aesthetics, como por ejemplo el color o el tamaño (de los puntos … o de las lineas o …)
Con geom_**() elegimos el tipo o geometría de gráfico. Hay muchos tipos de gráficos, así que habrán muchos geoms. Por ejemplo: geom_point(), geom_line(), geom_ …
Estas 3 ideas son las principales para entender ggplot2. Después hay muchas más opciones y elementos que serán muy importantes para conseguir un buen gráfico, pero en cierta forma son secundarias; por ejemplo, los títulos, los ejes, las escalas, el tema etc… lo iremos viendo poco a poco.
Afiancemos las ideas principales de la visualización con ggplot2. ¿Piensa que hará la siguiente linea de código?
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_line()
La primera parte de la instrucción es igual a la anterior: queremos un gráfico con el data.frame iris y queremos asociar la variable Sepal.Length con el eje x, con la propiedad aesthetic eje x y Petal.Length con el eje y; pero le hemos pedido un gráfico de lineas (geom_line()). En este caso hacer un gráfico de lineas no tiene mucho sentido, pero si se lo pedimos a R, este nos hace caso y nos lo muestra.
Ya dije que una de las características importantes de ggplot2 es que funciona por capas que se van superponiendo; para ir añadiendo capas a nuestro gráfico tenemos que usar el símbolo +. Por ejemplo si quisiéramos ver los puntos y las lineas ¿Cómo lo hacemos?
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_line()
Tampoco son muy útiles la lineas en este gráfico.
Otra geometría o geom_() que se usa mucho es geom_smooth(). Probémoslo:
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_smooth()
Del gráfico puede inferirse que hay una relación, no lineal, pero sí directa o positiva entre la longitud del sépalo y del pétalo; pero también se aprecia que hay al menos dos grupos distintos de lirios. Hay un grupo de observaciones cuyo pétalo parece ser claramente menor que el del resto de lirios. Veamos si esto se debe o esta asociado al tipo de lirio, recuerda que hay 3 tipos de lirios, asociados a la variable iris$Species. Para verlo en nuestro gráfico lo que vamos a hacer es asociar/mapear la variable Species con la aesthetics color:
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) + geom_point()
Pues parece que sí, que la especie de lirios “setosa” es más pequeña, al menos en longitud, del sépalo, pero sobre todo del pétalo.
La variable Species podríamos haberla asociado a la estética tamaño (size), o a la estética forma (shape) pero no sería tan útil ni quedaría tan bonito el gráfico. Fíjate que incluso R nos avisa de que asociar la propiedad o aesthetic tamaño con una variable categórica como Species no es muy recomendable.
ggplot(iris, aes(Sepal.Length, Petal.Length, size = Species)) + geom_point()
#> Warning: Using size for a discrete variable is not advised.
También podemos asociar la variable Species a la estética “forma”(shape). Lo hacemos en la expresión de más abajo. Como veis, ahora las diferencias entre especies de lirios no se aprecian tan bien como cuando usábamos color = Species
ggplot(iris, aes(Sepal.Length, Petal.Length, shape = Species)) + geom_point()
Os va a costar hacer gráficos, normal!!!, pero espero que la idea principal ya la tengáis. Lo que pasa es que no os he contado todo, en realidad es un poco más complejo y versátil. Lo medio explico en el siguiente apartado.
Ya tenéis las ideas principales para hacer gráficos con ggplot2, pero no os lo he contado todo, tampoco lo voy a hacer ahora, pero si contaré las cosas de una forma diferente para que tengáis más flexibilidad/versatilidad a la hora de hacer gráficos. Si queréis saber toda la verdad2 tendréis que ir al libro de Hadley, concretamente aquí.
La forma que os he contado de hacer gráficos ggplot2 es la que veréis habitualmente, yo también hago mis gráficos así, solo que para entender mejor el funcionamiento, la sintaxis de ggplot2, os lo tengo que contar otra vez de una forma un poco diferente o ampliada.
Un gráfico de ggplot2 se inicia llamando a la función ggplot() eso es cierto y también es verdad que generalmente dentro de ggplot() se indica el data.frame que vas a utilizar y con aes() que variables vas a usar y con que elementos visuales o estéticos quieres asociar cada una de la variables que vas a utilizar3. Correcto, pero …. en realidad un gráfico ggplot2 se hace por capas, cada capa se especifica con una función de la familia geom_xx(), así que en realidad los datos y las aes() se “deberían” especificar dentro de la función geom_xx()`. Parece un poco de lío pero en cuanto lo entiendas es muy fácil y te puede dar más flexibilidad a la hora de hacer tus gráficos. Empecemos: ¿recuerdas que hacen las lineas/expresiones de abajo?
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point()
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_line()
Podemos pensar que las funciones que hacen la representación gráfica realmente son las geom_xx(); es ahí donde deberíamos especificar los datos y variables/estéticas que queremos usar, pero si no las especificamos en la función geom(), entonces, ggplot2 mirará a ver si existen, si están especificados, dentro de ggplot().
Ahora que ya sabemos el funcionamiento básico de ggplot2, veamos algunos detalles mediante algunos ejemplos.Hasta ahora hemos especificado el data.frame que queremos graficar con ggplot(data = my_df) o con ggplot(my_df) y las variables que queremos ver, y a que propiedad estética queremos asociarla, con la función aes() dentro de ggplot(). Si lo hacemos así, todos los geoms_xx() que utilicemos compartirán el conjunto de datos y las variables/estéticas a mappear y mostrar; pero a veces, en gráficos más complejos podemos querer hacer que cada geom_xx() muestre datos y/o variables distintas.
Entender que cada geom_xx() puede estar asociado a distintos data.frames y/o variables es importante para tener más versatilidad con ggplot2.Por ejemplo, las siguientes tres expresiones hacen el mismo gráfico. Se suele utilizar la primera expresión, pero la segunda y tercera expresiones son “más flexibles”, aunque es verdad que si sólo se utiliza un geom_xx() no ganamos nada por usar la segunda o tercera expresión, pero no será el caso si en nuestro gráfico necesitamos usar varios geom_xx()
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point()
ggplot(iris) + geom_point(aes(Sepal.Length, Petal.Length))
ggplot() + geom_point(data = iris, aes(Sepal.Length, Petal.Length))
Fíjate, como detalle, pero importante, que si utilizas la tercera expresión; es decir, si especificas los datos dentro de la función geom_xx(), es necesario poner el nombre del argumento ; es decir, debes poner data = iris, no puedes poner solo iris. Yo me olvido siempre de este detalle4.
En este caso (como el gráfico solo tiene una capa, como sólo usamos un geom(_xx)) no ganamos por usar la segunda o tercera expresión; PERO, cuando usemos varios geom_xx() esto nos dará muchas posibilidades para nuestro gráfico.
Intenta descubrir las diferencias y funcionamiento de las 3 siguientes instrucciones. Recuerda que puedes correr las instrucciones en R para ver que hacen exactamente.
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) + geom_point() + geom_smooth()
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point(aes(color = Species)) + geom_smooth()
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_smooth(aes(color = Species))
Veámoslas una a una:
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) + geom_point() + geom_smooth()
En este caso los 2 geoms comparten el conjunto de datos (iris) y las variables/estéticas a graficar
geom_point()ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point(aes(color = Species)) + geom_smooth()
geom_smooth()ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_smooth(aes(color = Species))
Espero, seguro!!, que te has dado cuenta de que si especificas el data.frame y las variables/estéticas dentro de ggplot() esto afectará a todos los geoms del gráfico; pero lo que se especifique dentro de un geom_xx() solo afecta a esa geometría.
Otro ejemplo para entenderlo, ¿por qué no funciona la siguiente expresión?
ggplot(iris) + geom_point(aes(Sepal.Length, Petal.Length)) + geom_smooth(aes(color = Species))
Pues porque para poder representar la linea suavizada se utiliza geom_smooth(), y geom_smooth() necesita, al menos variables asociadas a las estéticas x e y. Como veis, dentro de geom_smooth() solo hemos especificado la estética “color” y tampoco hemos especificado que variables se asocian con x e y en la función ggplot(), así que geom_smooth() no puede hacer su trabajo, le faltan los “datos” de x e y para calcular/obtener la linea suavizada.
Es más fácil darse cuenta, con otros ejemplos, en la siguientes expresiones, que tampoco funcionarán5 si intentáis correrlas en vuestro ordenador:
ggplot(aes(Sepal.Length, Petal.Length)) + geom_point(data = iris) + geom_line()
ggplot() + geom_point(data = iris, aes(Sepal.Length, Petal.Length)) + geom_line(aes(Sepal.Length, Petal.Length))
ggplot() + geom_point(data = iris, aes(Sepal.Length, Petal.Length)) + geom_line()
Otro ejemplo: hagamos algo más marciano/complicado. Supón que quieres hacer un gráfico diferenciando los puntos por color para las tres especies de lirios, pero quieres que solo se vea la linea suavizada para las dos especies más grandes (virginica y versicolor). Los lirios más pequeños son los de la clase setosa. Igual se puede hacer de otra forma pero la que me viene a la cabeza es hacer lo siguiente:
Primero, crear un dataset que solo contenga a los lirios grandes, los de las especies virginica y versicolor.
iris2 <- iris %>% filter(Species != "setosa") #- me quedo con los lirios que no son de clase "setosa"
Para después, conseguir hacer el gráfico con cualquiera de las 2 expresiones siguientes. Prefiero la segunda porque hay que teclear/escribir menos, pero puede que sea más didáctica la primera.
ggplot() + geom_point(data = iris, aes(Sepal.Length, Petal.Length, color = Species)) + geom_smooth(data = iris2, aes(Sepal.Length, Petal.Length) )
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point(aes(color = Species)) + geom_smooth(data = iris2)
Otro ejemplo más: ¿y si quisiéramos que las 2 especies grandes se representen con el mismo color?. Hay varias soluciones, una de las más marcianas es la que propongo abajo, pero os ayudará a entender ggplot2
Primero voy a crear un nuevo data.frame sólo con las observaciones de los lirios pequeños, los de la clase setosa.
iris_setosa <- iris %>% filter(Species == "setosa") #- me quedo con los lirios pequeños, los de clase "setosa"
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_point(data = iris_setosa, aes(color = Species)) + geom_smooth(data = iris2,aes(Sepal.Length, Petal.Length) )
Otra solución, quizás más lógica, consiste en primero agrupar las 2 especies de lirios grandes (versicolor y virginica) en una sola clase.
iris_solo_2_clases <- iris %>% mutate(Species_2 = ifelse(Species %in% c("versicolor", "virginica"), "versi_virgi", "setosa"))
Para después hacer el gráfico; además el gráfico lo podemos hacer al menos de 2 maneras, la segunda mucho mejor, la primera expresión es un poco enrevesada:
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_point(data = iris_setosa, aes(color = Species)) + geom_smooth(data = iris_solo_2_clases,aes(Sepal.Length, Petal.Length, color = Species_2) )
ggplot(iris_solo_2_clases, aes(Sepal.Length, Petal.Length, color = Species_2)) + geom_point() + geom_smooth()
Como veis en ggplot2 hay varias maneras de hacer el mismo gráfico, esto al principio puede abrumar/molestar, pero muestra la flexibilidad de la sintaxis.
Para ir acabando con la “filosofía”/sintaxis/gramática de ggplot2 intenta imaginar que gráficos hacen las 6 expresiones de más abajo. Si no puedes, recuerda que siempre puedes ejecutar las ordenes en el ordenador. Fíjate sobre todo en la tercera expresión
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_smooth()
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) + geom_point() + geom_smooth()
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) + geom_point(color = "purple") + geom_smooth()
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) + geom_point() + geom_smooth(color = "brown")
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_smooth(aes(color = Species))
ggplot(iris) + geom_point(aes(Sepal.Length, Petal.Length, color = Species) ) + geom_smooth(aes(Sepal.Length, Petal.Length, color = Species))
En la tercera expresión se especifica color = Species dentro de aes() en ggplot(), así que, de momento, todos los geoms del gráfico deberían diferenciar por especies de lirios usando el color, PERO, después se vuelve a usar el argumento color dentro de geom_point(), pero fíjate que no va dentro de de aes(), va fuera. Concretamente hacemos lo siguiente: geom_point(color = "purple"); es decir, para la capa de puntos y solo para la capa de puntos que se crea con geom_point(), estamos asociando la estética color, no a una variable, sino a un color fijo. Sin embargo, para la otra capa del gráfico, la que resulta de usar geom_smooth() sigue siendo valido que la estética color está asociada a la variable Species.
Un detalle, imagina que en un gráfico en el que has fijado 3 estéticas dentro de ggplot(aes()). En principio las 3 estéticas afectarán a todos los geom_xx() que utilices en tu gráfico. Si quieres que, por ejemplo, la estética color no afecte a un geom concreto, puedes hacer lo siguiente: geom_xx(aes(color = NULL)) `
Como puedes imaginar aún tenemos que ver más elementos de ggplot2. Como mínimo los títulos y leyendas, los ejes, el tema, coordenadas, etc… vamos a ello!!
Ya hemos presentado los principales elementos de los gráficos hechos con ggplot2, los que tienen que ver con la representación de las variables, pero es evidente que un gráfico tiene muchos más elementos, y lógicamente hay que conocerlos un poco para poder ajustar los gráficos a nuestras necesidades/objetivos y para mejorar la calidad y claridad visual de nuestros gráficos. Ejemplos de otros elementos son: títulos del gráfico y de los ejes, “theme” del gráfico, small multiples o faceting, anotaciones etc…
En está sección iremos más rápido presentándose solo algunos ejemplo, conceptos y aclaraciones. Para conocer más de cada uno de estos elementos de un gráfico ggplot puedes acudir a la referencia oficial de los elementos y funciones de ggplot2.
Ya dijimos que los gráficos ggplot se compone de capas o layers. Para nosotros, hasta ahora, una capa estaba compuesta de 3 elementos:
un conjunto de datos
un conjunto de variable mapeadas con aes() a propiedades estéticas
una geometría, con geom_xx()
No en todos los geoms se pueden especificar todas las características estéticas. Para ver que estéticas admite cada geom tendrás que mirar la ayuda de cada geom. En este post se puede ver fácilmente que que características estéticas admite cada geom.
Esto es lo básico que hay que saber, pero en realidad una capa necesita de dos elementos más: una stat (o transformación estadística) y una posición. estos dos últimos elementos son necesarios pero el podríamos seguir haciendo gráficos con ggplot2 sin utilizarlos. ¿Por qué? pues porque si en una capa no los especificamos, lo hace ggplot2 por defecto; pero si conocemos como usar estos elementos nos dará más flexibilidad a la hora de hacer ggplots.
Generalmente las capas se van añadiendo con la familia de funciones geom_xx(), PERO también se pueden añadir capas con otra familia de funciones stat_xx().
Aparte de estos cinco elementos los gráficos ggplot pueden tener más elementos. Veamos los uno a uno.
Es evidente que un gráfico para ser efectivo y mostrar su mensaje con claridad debe tener un titulo y/o subtitulo ilustrativo y debe mostrar información relevante en los ejes X e Y. Este tipo de elementos pueden modificarse de varias maneras, pero nos centraremos en la función labs().
Fíjate que con la función labs() de labels podemos cambiar los títulos del gráfico, de los ejes y también de las leyendas. En los títulos (tanto del gráfico, como de los ejes y leyendas) también se pueden cambiar otras características; por ejemplo, cambiar el tamaño, la fuente o el color, pero eso será tarea de otra función de ggplot2: el grupo de funciones theme_(). Pero el tema o theme de los gráficos lo veremos en el siguiente apartado.
Tomemos el siguiente gráfico como referencia y sobre él iremos añadiendo elementos:
p <- ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) + geom_point()
p
Con la función labs() podemos añadirle un título, subtitulo, pie de gráfico o caption. También podemos cambiar el título de los ejes X e Y, así como también el titulo de la leyenda para color, o para otras estéticas que utilicemos en el gráfico.
Es suficiente con ver un ejemplo:
p + labs(title = "Gráfico 1: Longitud del sépalo frente al pétalo",
subtitle = "(diferenciando por especie de lirio)",
caption = "Datos provenientes del Iris dataset",
x = "Longitud del sépalo",
y = "Longitud del pétalo",
color = "Especie de lirio")
Si quisieras eliminar completamente los títulos del eje X podrías hacerlo en el anterior chunk fijando x = NULL, dentro de la función labs(); alternativamente se pueden usar las funciones auxiliares xlab() e ylab()
p + labs(color = NULL, x = NULL) #- borra el título de la leyenda y del eje X
p + xlab(NULL) + ylab(NULL) #- elimina títulos de los ejes X e Y
Themes control the display of all non-data elements of the plot. You can override all settings with a complete theme like theme_bw(), or choose to tweak individual settings by using theme() and the element_ functions. Use theme_set() to modify the active theme, affecting all future plots.
Para cambiar detalles de la apariencia del gráfico como el tamaño, fuentes y color de los títulos, pero también de los puntos, las lineas, el fondo del gráfico, la apariencia de las grid-lines, el lugar para las leyendas, etc… etc… contamos con las “funciones de tema”; todas ellas comienzan con theme_()
En general con las funciones theme_() podemos cambiar/ajustar cualquier elemento del gráfico, con la excepción de la propia representación de los datos (ya sabemos que esto se hacen con las funciones `geom_()). Estos elementos afectan a la apariencia y detalles del gráfico, pero no a la relación entre variables que se muestra realmente en el gráfico.
Para empezar a entender que hacen las funciones relacionadas con el theme, señalar que ggplot2 incorpora un conjunto de “temas” que podemos utilizar para cambiar la apariencia del gráfico a nuestro gusto. Puedes verlos todos aquí. El tema que usa por defecto ggplot2 es theme_gray(). Veámoslos en acción:
p + theme_gray() #- tema por defecto
p + theme_light()
p + theme_dark()
p + theme_classic()
p + theme_minimal()
p + theme_void()
El paquete de R ggthemes incorpora una amplia lista de temas adicionales, algunos de ellos tratan de replicar el estilo de corporaciones famosas como The Economist o Stata. Veamos algunos:
library(ggthemes)
p + theme_economist()
p + theme_fivethirtyeight()
p + theme_stata()
p + theme_solarized()
También podemos definir un tema propio para que el gráfico se ajuste los más posible a nuestras preferencias.
# define custom theme
my_theme <- theme(axis.text.x = element_text(colour = "grey20", size = 12, angle = 90, hjust = 0.5, vjust = 0.5), axis.text.y = element_text(colour = "grey20", size = 12),
text = element_text(size = 16))
p + my_theme
Se puede fijar el tema/theme de los gráficos con la función theme_set(). Por ejemplo:
theme_set(theme_minimal() ) #- un tema concreto
theme_set(theme_minimal() + theme(axis.text.x=element_blank(), axis.ticks.x=element_blank())) #- un tema modificando algunas opciones, que ele eje x no muestre ticks ni escalas
Si quieres volver al theme por defecto:
theme_set(theme_gray())
Ejemplos de algunos elementos cuya apariencia que se pueden cambiar con theme()
p + theme(legend.position = "none") #- que no aparezca leyenda
p + theme(legend.position = "bottom") #- leyenda abajo
p + theme(legend.direction = "horizontal") #- leyenda horizontal!!
p + theme(legend.title = element_text(size = 22)) #- título de la leyenda a 22
p + theme(legend.key.size = unit(2.4, "cm")) #- tamaño de los cuadros de la leyenda
p + theme(text = element_text(size = 20, face = "bold")) #- cambiar el tamaño de todos los elementos de texto
p + theme(text = element_text(face = "bold")) #- pone en negrita todos los elementos de texto
p + theme(axis.text.x = element_text(colour = "pink", size = 12, angle = 90, hjust = 0.5, vjust = 0.5)) # apariencia de la escala del eje x
p + theme(axis.title.y = element_text(size=25, angle = 45)) #- tamaño y angulo del texto del eje Y
p + theme(plot.subtitle = element_text(hjust = 3)) #- posición horizontal del subtitulo (si lo tuviese)
p + theme(plot.caption = element_text(hjust = 3)) #- posición vertical del pie de gráfico (si lo tuviese)
p + theme(panel.background = element_rect(fill = "green", colour = "pink", linetype = "longdash", size = 3.5))
p + theme(panel.background = element_blank())
p + theme(panel.background = NULL)
p + theme(plot.background = element_rect(fill = "pink", colour = "purple", linetype = "dotted", size = 7))
Si quieres ver todos las características que controla y que por tanto puedes modificar con theme(), usa la ayuda de la función theme() o haz:
args(theme)
En general, si quieres cambiar algún elemento has de hacer theme(elemento = element_text()). Si quieres eliminar por completo algún elemento del gráfico, por ejemplo las grid-lines del gráfico: theme(panel.grid = element_blank())
Evidentemente todo esto es imposible de aprender, sólo tienes que saber que cualquier elemento del gráfico se puede cambiar y tienes que saber buscar e interpretar la ayuda.
Se muy poco de escalas de color, pero si quieres ver los 657 colores que tienen un nombre en R:
aa <- as.data.frame(colours())
También es interesante este paquete que agrupa un conjunto amplio de paletas de colores para usar en R.
Por último, no se si conocéis el webcomic XKCD. Pues en R también hay un paquete y un theme para hacer gráficos al estilo XKCD. Es el paquete xkcd cuyo autor es Emilio Torres-Manzanera de la Universidad de Oviedo y aquí podéis ver algunos gráficos hechos con este estilo en R. Desafortunadamente no me ha salido, así que lo dejo; pero justo al día siguiente vi este tweet que hace algo parecido con datos de los Simpsons y su código sí funciona, además simula el estilo desde cero. Lo haremos en clase?!
El sistema gráfico de ggplot2 incorpora una técnica especial llamada “faceting” que permite dividir un gráfico en múltiples gráficos, cada uno de esos múltiples gráficos se realiza sólo para las observaciones de una de los valores de una variable categórica (o factor) incluido en el conjunto de datos. Es más fácil hacerlo que explicarlo/escribirlo.
Por ejemplo, en iris tenemos la variable Species, que es categórica. Lo que se con el “facetting” es dividir el dataset en grupos y hacer el mismo gráfico para cada uno de los grupos. los grupos se definen en función de los valores de la variable Species. Recuerda que hay 3 tipos de lirios o tres especies de lirios.
Para hacer un “facetting graph” podemos usar las funciones facet_wrap() y facet_grid().
Por ejemplo, con la función facet_grid() puedes elegir entre hacer los small multiples por filas o columnas. Empecemos por columnas. Además, con facet_grid() se pueden usar varias sintaxis, pero la que aparece en la cheatsheet actual de ggplot2 y, por tanto, la recomendada es las que ves en la segunda linea:
#p + facet_grid( . ~ Species) # old sintaxis
p + facet_grid(cols = vars(Species)) # gráficos x columnas, separando por valores de 'Species'
Ahora por filas:
p + facet_grid(rows = vars(Species)) # gráficos x filas
También podemos utilizar la función facet_wrap(). Esta función reparte los small multiples en una rejilla con forma de matriz. Además si en el dataset hubiesen dos variables categóricas podríamos hacer que una de ellas sirviese para llenar las filas y la otra las columnas:
p + facet_wrap(vars(Species), nrow = 2, ncol = 2) # graf x filas y columnas
Además si en el dataset hubiesen dos variables categóricas podríamos hacer que una de ellas sirviese para llenar las filas y la otra las columnas.
Como iris sólo tiene una variable categórica (Species) vamos a discretizar una de las variable continuas. Por ejemplo la anchura del pétalo, crearemos una nueva variable dividiendo las observaciones de Petal.Width en 2 categorías, por encima y por debajo de la media de su media. Además lo vamos a hacer con R-base. Seguro que hay mejores formas, por ejemplo
iris <- iris
iris$new_variable <- cut(iris$Petal.Width,
breaks = c(-Inf, mean(iris$Petal.Width), Inf),
labels = c("debajo-media", "arriba-media"))
Ahora ya tenemos dos variable discreta y podemos que puede hacer facet_wrap()
ggplot(iris) + geom_point( aes(Sepal.Length, Petal.Length, color = Species)) +
facet_wrap(vars(Species, new_variable), nrow = 2, ncol = 3) # graf x filas y columnas
No salen 6 grupos porque habrán algunos sin observaciones. Por ejemplo los lirios de la clase setosa siempre tiene el ancho de su pétalo por debajo de la media ¿Podríamos arreglarlo para que se viesen los 6 grupos?
Podemos ajustar las escalas de los ejes para que sean comunes para cada small multiple (la opción por defecto) o dejar que las escalas de cada gráfico varíen en función del rango de los datos representados:
p + facet_grid(rows = vars(Species)) #- escalas comunes
p + facet_grid(rows = vars(Species), scales = "free") #- las escalas de cada small pueden variar
p + facet_grid(rows = vars(Species), scales = "free_y") #- solo puede variar la escala del eje y
Solo muestro el resultado de la segunda expresión:
Un truquito/consejo: the margin argument in #ggplot2 facet_grid() for adding margins to your plots. It makes comparison easier across panels. #rstats >https://twitter.com/WeAreRLadies/status/1123109094422921216/photo/1>
Otro truco, esta vez avanzado: Un gist para poner labels a los smalls: https://gist.github.com/padpadpadpad/dc1f4520e4f9530b2c70fed0e4a425e9
Annotations are a special type of layer that don’t inherit global settings from the plot. They are used to add fixed reference data to plots.
Las anotaciones en los gráficos permiten resaltar algún fenómenos o observación de interés y son importantes a la hora de contar historias (storytelling) con los gráficos y visualizaciones.
En el entorno `ggplot2 podemos hacer anotaciones en nuestro gráficos de varias maneras, por ejemplo con annotate(). Aunque conceptualmente, como señala Hadley, las anotaciones son metadatos, desde el punto de vista práctico se usan los mismas funciones o geoms para manipularlos.
Cambien existen algunas funciones auxiliares en ggplot2 y paquetes específicos para hacer anotaciones en gráficos ggplot. Por ejemplo, cuando se hacen anotaciones en algunas o todas de las observaciones en un gráfico de puntos es fácil que las anotaciones caigan unas encima de otras, el paquete ggrepel permite aliviar este problema.
Utilicemos la función annotate(). Por ejemplo:
p + annotate(geom = "text", x = 6, y = 2, label = "Una anotación", size = 5) +
annotate("rect", xmin = 6, xmax = 7,ymin = -Inf, ymax = Inf, alpha = 0.2, fill = "pink") +
annotate("segment", x = 5, xend = 7, y = 6, yend = 8, colour = "blue")
Agregar texto a un gráfico es una de las formas más comunes de anotación, por ejemplo para señalizar e identificar observaciones anómalas, pero añadir texto no es fácil, otra vez según Hadley, por la forma en la que R maneja las fuentes.
La función principal para el etiquetado de gráficos es geom_text(). Por ejemplo:
p + geom_text(aes(label = Species))
También podíamos haber añadido el valor de la longitud del pétalo
p + geom_text(aes(label = Petal.Length))
Hemos añadido a cada observación un texto, proveniente de alguna de las variables de iris. Este gráfico no es muy útil, pero la técnica sí. Imagina que queremos marcar los lirios 45 y 1406. Podemos hacer lo siguiente:
iris_x <- iris[c(45, 140),] #- seleccionamos el lirio 45 y el 140 (con R-base!!)
p + geom_text(data = iris_x, aes(label = Species), color = "black", size = 5)
Podemos ajustar la posición y tamaño del texto, etc.. Por ejemplo, podemos cambiar la alineación de las anotaciones con con hjust(“left”, “center”, “right”, “inward”, “outward”) y vjust (“bottom”, “middle”, “top”, “inward”, “outward”).
Podemos añadir lineas:
p + geom_vline(xintercept = 6)
p + geom_hline(yintercept = 5, size = 1.7, colour = "black", linetype = "dashed")
p + geom_abline(intercept = 0.7, slope = 0.4, size = 2)
Si quieres modificar el recorrido de los ejes, los “límites” de los ejes, puedes usar lims(). Para los ejes X e Y hay dos funciones auxiliares: xlim() e ylim().
p + lims(color = c("setosa"), x = c(NA,6), y = c(4,8))
p + xlim(c (4, 6)) + ylim(c(NA, 5))
# se puede dar la vuelta a los ejes
p + xlim(c (7, 3)) + ylim(c(NA, 5))
Los limites o dominio del gráfico suelen obtenerse automáticamente de los datos, pero, otra vez according to Hadley, hay dos razones por las que podemos estar interesados en cambiar los límites del gráfico: 1) centrarnos en una región especifica del gráfico 2) aumentar los límites para que varios gráficos ajusten sus escalas.
Por ejemplo, si después de hacer un gráfico quieres centrarte sólo en una parte; es decir, hacer un zoom sobre una parte del gráfico, tenemos 2 alternativas:
p + xlim(c(4, 5)) + ylim(c(NA, 5)) #- cuidado, se pueden borrar observaciones
Con este enfoque tienes que tener cuidado, ya que si por ejemplo después utilizar alguna transformación estadística como por ejemplo geom_smooth(), las observaciones eliminadas al ajustar los límites no entrarán en el cálculo estadístico.
p + geom_smooth(color = "purple")
p + geom_smooth(color = "purple") + xlim(c(4, 5.7)) + ylim(c(1.5, 5)) # deletes points
coord_cartesian().p + geom_smooth(color = "purple")
p + geom_smooth(color = "purple") + coord_cartesian(xlim = c(4, 5.7), ylim = c(1.5, 5))
Scales control the details of how data values are translated to visual properties. Override the default scales to tweak details like the axis labels or legend keys, or to use a completely different translation from data to aesthetic. labs() and lims() are convenient helpers for the most common adjustments to the labels and limits.
Las escalas permiten leer/interpretar los un gráfico; permiten interpretar los elementos geométricos (por ejemplo en nuestro gráfico, los puntos) en función de los valores originales de las observaciones. Las escalas son un elemento más de los gráficos ggplot, se producen/controlan con la familia de funciones scale_xx()
En ggplot2 las escalas o guías se producen automáticamente, no vemos que hagamos nada, pero under the hood se están fijando con la familia de funciones sale_xx() que son las que controlan como se mapean los valores de las variables con las propiedades estéticas de nuestro gráfico (por ejemplo el eje X), de forma que podamos interpretar la posición de los distintos puntos puntos mirando las escalas. Las escalas también construyen los elementos que permiten leer/interpretar los gráficos: los ejes y las leyendas.
Como ggplot2 hace el mapeo y genera las escalas y leyendas automáticamente, en la práctica podemos hacer gráficos sin saber como funcionan y, por tanto sin saber manipular, este elemento de un gráfico ggplot: las escalas. Pero si aprendemos a manipularlas nos dará más flexibilidad a la hora de utilizar ggplot2.
En muchos tipos de datos es importante pararse a pensar cual es la mejor escala para representar las variables. Quizás sea conveniente cambiar la escala de un eje para distribuir mejor las observaciones en el espacio, o para interpretar mejor las variaciones entre observaciones; por ejemplo la escala logarítmica o en porcentajes son a veces más apropiadas que las escalas originales.
En realidad, para cada par variable/estética representada en un gráfico ggplot es necesaria una escala, y tendría que fijarse con una de las funciones de la familia scale_xx(). Realmente cuando hacemos este gráfico, en el que asociamos 3 variables a 3 propiedades estéticas con aes(), se necesitaría especificar las escalas de las 3 variables:
p <- ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point(aes (color = Species))
Bien, pero entonces ¿por qué no lo hacemos?, ¿por qué no especificamos las escalas? Pues porque lo hace ggplot2 por nosotros. En realidad cuando ejecutamos la expresión anterior, realmente se está haciendo lo siguiente:
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point(aes (color = Species)) +
scale_x_continuous() +
scale_y_continuous() +
scale_colour_discrete()
Es decir, ggplot2 asigna a cada variable una escala, a las variables continuas les asigna una escala continua y a las categóricas una escala discreta. PERO, si queremos, si lo consideramos apropiado podemos cambiar la escala. Por ejemplo:
p + scale_y_reverse() + scale_colour_grey()
p + scale_x_sqrt() + scale_y_log10()
p + scale_x_continuous(trans = "log")
p + scale_colour_brewer(palette = "Dark2")
También se pueden modificar lo que vemos en los escalas. Antes vamos a modificar los títulos de los ejes y leyendas.
p <- p + labs(x = "Eje X", y = "Eje Y", colour = "Leyenda\npara el color")
De momento la escala del eje X varia aproximadamente de 3 a 8. Los títulos de la escala del eje X sólo muestra los valores 5, 6, 7 y 8. Vamos a modificar “el texto”, los números que se ven y que sirven de guía para la escala del eje X:
p + scale_x_continuous(breaks = seq(3, 10, 0.5), limits = c(3, 10))
En el eje Y se ven los números 2, 4 y 6. Cambiemos los labels de su escala (no del eje Y, sino de la escala del eje Y):
p + scale_y_continuous(breaks = seq(0, 12, 0.25), label = scales::dollar)
También se pueden modificar los de la leyenda para el color:
p + scale_color_manual(values = c("purple", "pink", "red2"), name = "Especies\nde lirios")
Si hubiese usado una variable discreta asociada a la estética “shape”, tendríamos que usar scale_shape_discrete(), si la variable asociada a shape fuese continua: scale_shape_continuous()
¿Y si hubiésemos usado una variable continua para la estética “fill”? Pues scale_fill_continuous()
• scale_continuous() • scale_discrete() • scale_ordinal() • scale_manual() • scale_{color/fill}brewer() • scale{color/fill}distiller() • scale{color/fill}_gradient()
Puede leerse en la web de ggplot2, concretamente aquí lo siguiente:
A layer combines data, aesthetic mapping, a geom (geometric object), a stat (statistical transformation), and a position adjustment. Typically, you will create layers using a geom_ function
PERO
A handful of layers are more easily specified with a stat_ function, drawing attention to the statistical transformation rather than the visual appearance. The computed variables can be mapped using stat().
Algunos gráficos, como los gráficos de puntos, no requieren del uso de transformaciones estadísticas de las observaciones, pero otros gráficos como rectas o curvas de predicción o como los boxplots o diagramas de caja sí. Podemos usar transformaciones estadísticas en gráficos ggplot con la familia de funciones stat_xx()
Cuando se hace un diagrama de caja o boxplot, no se representan las observaciones originales, sino que se muestran 5 estadísticos resumen de la distribución de los datos; es decir, se utiliza una transformación estadística. Cuando usábamos geom_smoth() tampoco representábamos con él los datos originales, sino una transformación estadística de estos. Concretamente la transformación estadística que utiliza geom_smoth() es genéricamente un “smoother”, calcula mediante una rolling-windows la media de y, condicionada a x.
Cada función geom_xx() que se utilicemos, en realidad necesita de un stat_xx(), entonces ¿por qué nunca lo hemos usado/especificado nosotros? La razón es casi siempre la misma, con ggplot2: es un sistema muy completo pero aún así, una vez lo entiendes, hacer gráficos con el es relativamente fácil y rápido, pero eso es porque under the hood ggplot2 hace muchas cosas por nosotros. En concreto, cada vez que usamos un geom_xx() en realidad `ggplot2 está fijando una transformación estadística por defecto por nosotros.
Por ejemplo, ¿cual es la transformación estadística que se usa por defecto en geom_point()? Ninguna, bueno, en realidad usa stat = "identity"
Cuando hacíamos este gráfico:
ggplot(iris, aes(Petal.Length, Sepal.Length)) + geom_point()
En realidad estábamos haciendo
ggplot(iris, aes(Petal.Length, Sepal.Length)) + geom_point(stat = "identity")
ggplot(iris, aes(Petal.Length, Sepal.Length)) + geom_point(stat = "unique") #- dejaría solo observaciones no repetidas
Podemos consultar las opciones por defecto completas de geom_point() aquí
Cada geom_xx() tiene un default statistic, pero podemos cambiarlo y especificar otra stat para adaptarlo a nuestras necesidades. Por ejemplo, the default statistic for geom_bar() is stat_bin() pero podemos usar otras stat. Otra vez parece un trabalenguas, pero cuando lo entiendes es fácil.
Por ejemplo, en nuestro gráfico de puntos, podemos usar otras transformaciones estadísticas, una de las que más sentido tiene es calcular medias móviles con un método de alisado (smoother)
p <- ggplot(iris, aes(Petal.Length, Sepal.Length, color = Species))
p + geom_point(stat = "identity")
p + geom_point(stat = "smooth", method = "auto")
Aunque en este caso es bastante más fácil hacerlo con:
p + geom_point() + geom_smooth()
p + geom_point() + stat_smooth()
p + geom_point() + stat_smooth(method = "lm", se = FALSE, size = 1)
p + geom_point() + geom_smooth(method = "lm", se = FALSE, size = 1)
p + geom_point() + geom_smooth(method = "lm", col = "#C42126", se = FALSE, size = 1)
Algunas transformaciones estadísticas útiles y en qué geoms están disponibles:
- stat_bin(): geom_bar(), geom_freqpoly(), geom_histogram()
- stat_bin2d(): geom_bin2d()
- stat_bindot(): geom_dotplot()
- stat_binhex(): geom_hex()
- stat_boxplot(): geom_boxplot()
- stat_contour(): geom_contour()
- stat_quantile(): geom_quantile()
- stat_smooth(): geom_smooth()
- stat_sum(): geom_count()
Es raro que tengamos que usar estas funciones stats_xx() directamente, pero si quieres ver que hacen exactamente conviene conocerlas para consultar la documentación de cómo se aplica exactamente cada transformación estadística a los datos.
Hay otras funciones stat_xx() que no se pueden con las funciones geom_xx():
- stat_ecdf(): compute a empirical cumulative distribution plot.
- stat_function(): compute y values from a function of x values.
- stat_summary(): summarise y values at distinct x values.
- stat_summary2d(), stat_summary_hex(): summarise binned values.
- stat_qq(): perform calculations for a quantile-quantile plot.
- stat_spoke(): convert angle and radius to position.
- stat_unique(): remove duplicated rows.
Veamos algunos ejemplos útiles:
Queremos que la media se represente como un punto, entonces usamos geom_point() pero no queremos representar los valores originales , sino la media, así que dentro de geom usamos la opción stat = summary
ggplot(iris, aes(Species, Sepal.Length)) +
geom_boxplot() +
geom_point(stat = "summary", fun.y = "mean", colour = "red", size = 4)
Se conseguiría los mismo usando directamente la función stat_summary() con la opción geom = “point”. Sí, en ggplot2 las cosas se pueden hacer de varias maneras!!
ggplot(iris, aes(Species, Sepal.Length)) +
geom_boxplot() +
stat_summary(geom = "point", fun.y = "mean", colour = "red", size = 4)
Otro ejemplo: el default stat de geom_histogram es stat = “bin”.
ggplot(iris, aes(Sepal.Length)) + geom_histogram()
ggplot(iris, aes(Sepal.Length)) + geom_histogram(aes(y = stat(count)))
ggplot(iris, aes(Sepal.Length)) + geom_histogram(stat = "count")
ggplot(iris, aes(Sepal.Length)) + geom_histogram(aes(y = stat(count / max(count))))
Bonus: Con stat_function() podemos dibujar curvas de densidad:
df <- tibble(x = c(-20, 20))
ggplot(df, aes(x = x)) +
stat_function(fun = dnorm, args = list(mean = 0, sd = 5), color = "black") +
stat_function(fun = dnorm, args = list(mean = 0, sd = 1), color = "red") +
stat_function(fun = dnorm, args = list(mean = 0, sd = 3), color = "blue")
All layers have a position adjustment that resolves overlapping geoms. Override the default by using the position argument to the geom_ or stat_ function.
Los ajustes de posición afectan a la posición de los elementos de una capa. Los gráficos en los que más se utilizan los ajustes de posición son los gráficos de barras. Su posición por defecto es position = “stack”. Se pueden cambiar con el argumento geom_bar(position = “xxxx”), aunque si usas las funcionesposition_xx()` tienes más flexibilidad:
ggplot(iris , aes(Species)) + geom_bar()
ggplot(mtcars, aes(cyl)) + geom_bar()
Para poder visualizar gráficos de barras con 2 variables,tenemos que usar otro dataset: mtcars
ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) + geom_bar() #- pos
ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) + geom_bar(position = "fill")
ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) + geom_bar(position = "dodge")
ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) + geom_bar(position = position_dodge2(preserve = "single"))
Por ejemplo, podemos modificar la posición por defecto de nuestro gráfico de puntos:
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_point(position = "jitter", color = "pink")
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + geom_jitter( color = "pink")
The coordinate system determines how the x and y aesthetics combine to position elements in the plot. The default coordinate system is Cartesian (coord_cartesian()), which can be tweaked with coord_map(), coord_fixed(), coord_flip(), and coord_trans(), or completely replaced with coord_polar()
Por ejemplo: coord_fixed(). En nuestro gráfico, tanto la longitud del pétalo como del sépalo se miden en las mismas unidades, así que su ratio implícito es 1 a 1. Cambiemos el ratio de las coordenadas con coord_fixed()
p <- ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point()
p
p + coord_fixed(ratio = 1/3)
p + coord_fixed(ratio = 3/1)
La técnica del faceting es una fantástica herramienta para dividir un gráfico en varios, en principio en función de una variable categórica, si queremos usar una variable continua primero habría que discretizarla. PERO a veces lo que interesa es crear una figura compuesta de varios gráficos diferentes. Esto no es un elemento más de ggplot2 es una operación que hacemos sobre un grupo de varios gráficos.
Podemos hacerlo con varios paquetes:
gridExtra y su función grid.arrange()library(gridExtra)
p1 <- ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) + geom_point()
p2 <- ggplot(iris)+ aes(Species, Sepal.Length) + geom_boxplot()
grid.arrange(p1, p2, ncol = 2, widths = c(6.5, 3.5))
Además de los argumentos ncol, nrow y widths, con gridExtra se pueden hacer composiciones más complejas
patchworklibrary(patchwork)
p1 + p2 + plot_layout(ncol = 2)
cowplot. Este paquete también se puede utilizar para hacer anotaciones o para incorporar imágenes a nuestros gráficoslibrary(cowplot)
ggdraw() + draw_image("./imagenes/Captura.JPG") +
draw_plot(p1 + theme(legend.box.background = element_rect(color = "white")))
La mayoría de las veces, cuando creamos un gráfico lo vemos inmediatamente, pero también podemos asignarle un nombre y manipularlo más adelante.
p <- ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point()
p + geom_line()
Una vez que tienes el gráfico guardado como un objeto en el R environment puedes hacer varias cosas con él:
verlo en la pantalla con print()
guardarlo en un fichero en diferentes formatos. Piensa que estamos guardando el gráfico, la imagen, la representación del gráfico, no el objeto R.
Podemos usar la “Export Tab” en el Plot Pane de Rstudio. Lo grabará en baja resolución. También podemos cambiar las dimensiones (anchura y altura) del gráfico. Si vamos a utilizar el gráfico en Word es conveniente guardar el gráfico como Metafile.
Como alternativa podemos usar la función ggsave() que, ademas, nos permite cambiar el tamaño y la resolución del gráfico con los argumentos width, height y dpi. Nota: Los parámetros width and height también determinan el tamaño de la fuente del gráfico guardado.
ggsave("./graf_out/my_grafico_chulo.png", p, width = 15, height = 10)
ggsave("filename.png", plot = my_plot, width = 8, height = 6, units = "in", dpi = "retina")
# Tb funciona para figuras compuestas de varios gráficos
grafico_combinado <- grid.arrange(p1, p2, ncol = 2, widths = c(6, 4))
ggsave("fig_output/my_combo_plot.png", grafico_combinado, width = 10, dpi = 300)
saveRDS(), para luego leerlo con readRDS(). Aunque, ya que nos ponemos, es mejor guardar el script que genera el objeto. Sólo tendría sentido si fuese muy costoso, por ejemplo en términos de tiempo, reproducir el gráfico.saveRDS(p, "plot.rds")
my_valioso_grafico <- readRDS("plot.rds")
En está sección presentaremos algunos ejemplos de algunos de los gráficos más utilizados en el análisis de datos. Puedes ver listados más completos en:
Una serie de visualizaciones increíbles asociadas al proyecto tidy Tuesday:
Una plantilla que te puede ayudar a decidir qué gráfico usar:
Tutoriales ggplot2:
Scatter plot, gráfico de puntos o gráfico X-Y. Lo tenemos más que visto ya que el gráfico que hemos utilizado para explicar el funcionamiento de ggplot2ya lo hemos hecho al presentar ggplot2.
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
geom_point() +
labs(title = "Gráfico 1: Longitud del sépalo frente al pétalo",
subtitle = "(diferenciando por especie de lirio)",
caption = "Datos provenientes del Iris dataset",
x = "Longitud del sépalo",
y = "Longitud del pétalo",
color = "Especie de lirio")
Los gráficos de puntos se usan habitualmente para mostrar la relación entre dos variables continuas. En conjuntos de datos con muchas observaciones pueden tener un problema de “overplotting”. Esta situación ocurre cuando un puntos se dibuja encima de otros de forma que se oscurece la relación entre las variables
Hay varias formas de tratar este problema. Veámoslo con un ejemplo sacado de la web de ggplot2:
set.seed(1234)
df <- data.frame(x = rnorm(2000), y = rnorm(2000)) #- creamos un conjuto de datos con 2000 observaciones y 2 v.
p <- ggplot(df, aes(x, y)) + xlab(NULL) + ylab(NULL)
p + geom_point()
p + geom_point(shape = 1) # Hollow circles
p + geom_point(shape = ".") # Pixel sized
#- For larger datasets with more overplotting, you can use alpha blending (transparency) t
p + geom_point(alpha = 1 / 10)
De forma alternativa, podemos lidiar con el overploting utilizando otro enfoque, consiste en pensar en él como en un problema de densidad en 2 dimensiones y utilizar un hex-plot. En Un hex-plot se representan regiones (generalmente hexagonales) coloreadas en función del número de observaciones que caen en cada región, de forma que es equivalente a un histograma pero en 2d.
p + geom_bin2d()
p + geom_bin2d(bins = 10)
p + geom_hex()
p + geom_hex() + scale_fill_gradient2(low = "#132B43", high = "#56B1F7")
En este post utilizan hex-plots para mostrar las zonas desde donde tiran a canasta los jugadores NBA. En [este otro post] utilizan una combinación de geom_point(alpha = .2, pch = 15) + geom_density_2d() para analizar las puntuaciones de videojuegos. Además hace un uso avanzado de las escalas, al menos para mi, para que el gráfico sea fácil de visualizar.
Acaba de aparecer un nuevo geom: geom_pointdensity(). Como dicen en su repo de Github: “A cross between a scatter plot and a 2D density plot”.
#devtools::install_github("LKremer/ggpointdensity")
library(viridis)
library(ggpointdensity)
p + geom_pointdensity(adjust = 7) +
scale_color_viridis()
Si quieres saber más cosas sobre cómo hacer scatterplots con ggplot2 puedes hacerlo aquí o aquí.
Para visualizar como varían los valores de una variable continua en función de los valores de una variable categórica se usan generalmente boxplots o diagramas de caja. En estos casos geom_point() no es muy adecuado.
ggplot(iris, aes(x = Species, y = Sepal.Length)) + geom_point()
En general suele haber mucho “overplotting”: muchos puntos están trazados en la misma ubicación, y es difícil ver la distribución de estos. Hay tres técnicas/geoms útiles que ayudan a resolver el problema:
p <- ggplot(iris, aes(x = Species, y = Sepal.Length))
p + geom_boxplot()
p + geom_jitter()
p + geom_violin()
Cada método tiene sus puntos fuertes y débiles. Los boxplots resumen la mayor parte de la distribución con sólo cinco números, proporcionando un resumen muy útil de los datos, pero ocultan la forma de la distribución; por ejemplo, si la distribución fuese bimodal, no lo apreciaríamos. Los gráficos jitter muestran cada punto, pero sólo funcionan con conjuntos de datos relativamente pequeños. Una alternativa al boxplot son los gráficos de violín donde se estima y muestra la forma de la distribución de las observaciones, que puede tener problemas de interpretación.
También podemos combinar varios de estos geoms:
p + geom_boxplot() + geom_jitter(alpha = 0.4, color = "tomato")
p + geom_violin() + geom_jitter(alpha = 0.6, color = "tomato")
Vic:
Podemos colorear las cajas del gráfico incluyendo en las características estéticas la variable que utilizaremos para el relleno. Automáticamente se crea una leyenda para facilitar la lectura del gráfico, que podemos cambiar de posición o eliminar si se considera que no aporta información relevante.
# Diagrama de caja con color de relleno
ggplot(CPS1985, aes(x=gender, y=wage, fill=gender)) +
geom_boxplot() +
labs(x="Género", y="Salario", fill="Género") + # titulo ejes y leyenda
scale_x_discrete(labels=c("Hombre","Mujer")) + # etiquetas del eje x
scale_fill_discrete(labels=c("Hombre","Mujer")) # etiquetas claves leyenda
theme(legend.position="top") # cambio posición de leyenda
guides(fill=FALSE) # eliminamos la leyenda
coord_flip() # cambio dirección de las cajas
Por último, si queremos hacernos una idea de cómo se distribuyen nuestras observaciones/individuos respecto del diagrama de caja podemos hacer uso de la función position_jitter(). Cuando hay muchos datos las observaciones se superponen. La función position_jitter() lo que hace es añadir un pequeño “ruido” en cada posición. También podemos utilizar la geometría geom_jitter(). A continuación se muestran los diagramas de caja con estas dos opciones.
geom_histogram() and geom_freqpoly() show the distribution of continuous variables.
Histograms and frequency polygons show the distribution of a single numeric variable. They provide more information about the distribution of a single group than boxplots do, at the expense of needing more space.
ggplot(mpg, aes(hwy)) + geom_histogram() > stat_bin() using bins = 30. Pick better value with binwidth. ggplot(mpg, aes(hwy)) + geom_freqpoly() > stat_bin() using bins = 30. Pick better value with binwidth.
Both histograms and frequency polygons work in the same way: they bin the data, then count the number of observations in each bin. The only difference is the display: histograms use bars and frequency polygons use lines. You can control the width of the bins with the binwidth argument (if you don’t want evenly spaced bins you can use the breaks argument). It is very important to experiment with the bin width. The default just splits your data into 30 bins, which is unlikely to be the best choice
An alternative to the frequency polygon is the density plot, geom_density(). I’m not a fan of density plots because they are harder to interpret since the underlying computations are more complex. They also make assumptions that are not true for all data, namely that the underlying distribution is continuous, unbounded, and smooth.
To compare the distributions of different subgroups, you can map a categorical variable to either fill (for geom_histogram()) or colour (for geom_freqpoly()). It’s easier to compare distributions using the frequency polygon because the underlying perceptual task is easier. You can also use facetting: this makes comparisons a little harder, but it’s easier to see the distribution of each group
ggplot(mpg, aes(displ, colour = drv)) + geom_freqpoly(binwidth = 0.5) ggplot(mpg, aes(displ, fill = drv)) + geom_histogram(binwidth = 0.5) + facet_wrap(~drv, ncol = 1)
(Vic)Dos cosas a considerar del histograma anterior:
Por defecto, el número de intervalos es de 30. Es posible establecer el número de intervalos (bins), la amplitud del intervalo (binwidth) o fijar los puntos de corte de los intervalos (breaks).
El eje Y corresponde al número de observaciones (frecuencias absolutas). Si estamos interesados en representar un histogramas de forma que el área del mismo sume 1, entonces tenemos que cambiar la estética de la siguiente forma:
ggplot(CPS1985, aes(x=wage)) +
geom_histogram(aes(y=..density..))
geom_histogram(bins=20, color="white", fill="blue")
geom_histogram(binwidth=5, color="white", fill="blue", linetype=2)
y casi mejor con la densidad de frecuencias:
ggplot(CPS1985, aes(x=wage)) +
geom_freqpoly(bins=20, aes(y=..density.., color=gender)) +
labs(color="Género")
A continuación, vamos a añadir dos líneas para situar la media y la mediana.
ggplot(CPS1985, aes(x=wage)) +
geom_histogram(aes(fill=..count..), bins=20, color="white") +
geom_vline(aes(xintercept=mean(wage)), color="red") +
geom_vline(aes(xintercept=median(wage)), color= "darkgreen") +
labs(title = "Distribución del salario (dólares por hora)",
x = "Salario",
y = "Número de empleados") +
scale_fill_continuous(name="Empleados") +
theme_classic()
Añadimos la curva normal al histograma
ggplot(CPS1985, aes(x=wage)) +
geom_histogram(aes(y=..density..), bins=20, color="white", fill="grey") +
stat_function(fun = dnorm, colour = "red",
args = list(mean = mean(wage, na.rm = TRUE),
sd = sd(wage, na.rm = TRUE))) +
geom_density(color="blue")
Con el argumento expand_limits podemos evitar que la curva de densidad aparezca unida. Veámoslo con el siguiente ejemplo:
ggplot(CPS1985, aes(x=wage)) +
geom_histogram(aes(y=..density..), bins=20, color="white", fill="grey") +
stat_function(fun = dnorm, colour = "red",
args = list(mean = mean(wage, na.rm = TRUE),
sd = sd(wage, na.rm = TRUE))) +
geom_line(stat="density", color="blue") +
expand_limits(y=0)
http://www.sthda.com/english/wiki/ggplot2-histogram-plot-quick-start-guide-r-software-and-data-visualization
http://t-redactyl.io/blog/2016/02/creating-plots-in-r-using-ggplot2-part-7-histograms.html
Vic:El diagrama de barras, como ya sabemos, puede utilizarse para representar variables categóricas (atributos u ordinales) y variables cuantitativas discretas.
ggplot(CPS1985, aes(ethnicity)) + geom_bar()
geom_bar() shows the distribution of categorical variables.
The discrete analogue of the histogram is the bar chart, geom_bar(). It’s easy to use:
By default, ggplot makes a ‘counts’ barchart, meaning, it counts the frequency of items specified by the x aesthetic and plots it. In this format, you don’t need to specify the Y aesthetic. However, if you would like the make a bar chart of the absolute number, given by Y aesthetic, you need to set stat=“identity” inside the geom_bar.
plot1 <- ggplot(mtcars, aes(x=cyl)) + geom_bar() + labs(title="Frequency bar chart") # Y axis derived from counts of X item
print(plot1)
df <- data.frame(var=c("a", "b", "c"), nums=c(1:3))
plot2 <- ggplot(df, aes(x=var, y=nums)) + geom_bar(stat = "identity") # Y axis is explicit. 'stat=identity'
print(plot2)
Coloreamos cada barra con un color distinto:
ggplot(CPS1985, aes(ethnicity, fill=ethnicity)) +
geom_bar() +
labs(title="Diagrama de barras",
x= "Raza",
y="Empleados") +
scale_x_discrete(labels=c("Caucásico", "Hispano", "Otros"))
guides(fill=FALSE) #- eliminas leyenda
geom_text(stat='count',aes(label=..count..), vjust=-0.5, size=3) #- Incorporamos información sobre el número de casos en las barras correspondientes a cada categoría y eliminamos el eje Y.
interesados en ver cómo se distribuye el género según la raza.
ggplot(CPS1985, aes(ethnicity, fill=gender)) +
geom_bar() +
labs(title="Diagrama de barras",
x= "Raza",
y="Empleados") +
scale_x_discrete(labels=c("Caucásico", "Hispano", "Otros")) +
scale_fill_discrete("Género", labels=c("Hombre","Mujer"))
Otros colorspaces
scale_x_discrete(labels=c("Caucásico", "Hispano", "Otros")) +
scale_fill_manual(values=c("#FF0033", "#3300FF"),
"Género",
labels=c("Hombre","Mujer"))
escla de colorspacesscale_fill_manual(values = heat.colors(2),
"Género",
labels=c("Hombre","Mujer"))
Paletas de colorspaces scale_fill_brewer(palette = "Accent",
"Género",
labels=c("Hombre","Mujer"))
geom_text(stat='count',aes(label=..count..), GOOOOOD
position = "stack",
vjust=1,
size=2,
color="red")
El mismo diagrama de barras apilado pero ahora en porcentajes:
ggplot(CPS1985, aes(ethnicity,y = (..count..)/sum(..count..), fill=gender)) +
geom_bar() +
labs(title="Diagrama de barras",
x= "Raza",
y="Empleados") +
scale_x_discrete(labels=c("Caucásico", "Hispano", "Otros")) +
scale_fill_brewer(palette = "Accent",
"Género",
labels=c("Hombre","Mujer")) +
geom_text(stat="count",
aes(label = paste(round((..count..)/sum(..count..)*100), "%")),
position = "stack",
vjust=1,
size=2,
color="red")
Como hemos podido comprobar hasta ahora, cuando hacemos un diagrama de barras en el que consideramos más de una variable categórica, las barras aparecen apiladas (la opción por defecto es position = “stack”). Podemos hacer que las barras se sitúen unas junto a las otras con position = “dodge”.
ggplot(CPS1985, aes(ethnicity, fill=gender)) +
geom_bar(position="dodge") + # también: position=position_dodge()
Podemos simular gráficos de series temporales con geom_line() y geom_path(). Estos 2 geoms grafican lineas entre dos puntos de los datos. A line plot is constrained to produce lines that travel from left to right, while paths can go in any direction. Lines are typically used to explore how things change over time
Line and path plots are typically used for time series data. Line plots join the points from left to right, while path plots join them in the order that they appear in the dataset (in other words, a line plot is a path plot of the data sorted by x value). Line plots usually have time on the x-axis, showing how a single variable has changed over time. Path plots show how two variables have simultaneously changed over time, with time encoded in the way that observations are connected
ggplot(economics, aes(date, uempmed)) + geom_line()
If you have a scatterplot with a lot of noise, it can be hard to see the dominant pattern. In this case it’s useful to add a smoothed line to the plot with geom_smooth(). If you’re not interested in the confidence interval, turn it off with geom_smooth(se = FALSE).
An important argument to geom_smooth() is the method, which allows you to choose which type of model is used to fit the smooth curve:
method = “loess”, the default for small n, uses a smooth local regression (as described in ?loess). The wiggliness of the line is controlled by the span parameter, which ranges from 0 (exceedingly wiggly) to 1 (not so wiggly). Loess does not work well for large datasets (it’s O(n2) in memory), so an alternative smoothing algorithm is used when n is greater than 1,000. method = “lm” fits a linear model, giving the line of best fit. method = “rlm” works like lm(), but uses a robust fitting algorithm so that outliers don’t affect the fit as much. It’s part of the MASS package, so remember to load that first.
stat_smooth(se=FALSE) # líneas y bandas de suavizado (smooth)
geom tiene mucha flexibilidad
p + geom_smooth(method = "lm",
formula = y ~ poly(x,2),
se = FALSE,
size = 1.5)
Si pueed hacer un ejemplo con geom_smooth: It’s sometimes useful to map aesthetics to constants. For example, if you want to display multiple layers with varying parameters, you can “name” each layer:
ggplot(mpg, aes(displ, hwy)) +
geom_point() +
geom_smooth(aes(colour = "loess"), method = "loess", se = FALSE) +
geom_smooth(aes(colour = "lm"), method = "lm", se = FALSE) +
labs(colour = "Method")
Pie chart I Pie charts are surprisingly tricky to make I Stacked bar chart in polar coordinates
ggplot(mtcars, aes(x=factor(1), fill=factor(cyl))) +
geom_bar(width=1) + coord_polar(theta='y')
ggplot(data=iris, aes(x=Species, y=Petal.Width)) +
geom_violin(aes(fill=Species))
ggplot(data=iris, aes(x=Petal.Width)) +
geom_density(aes(fill=Species))
ggplot(data=cage, aes(x=title_year, y=imdb_score, label=mov
geom_point(alpha=0.5) +
geom_text(fontface='italic', size=2, vjust=1, nudge_y=0.1
geom_smooth()
scale_x_log10() +
scale_x_continuous(breaks=c(1e6, 1e8), labels=c('Low budget', 'Blockbuster'), trans='log10')
scale_x_log10() +
scale_color_continuous(name='Box office gross', breaks =
labels = c('2 million', '4 million
low = 'blue', high = 'red')
annotate('text', x=2e+08, y=8.7, label='Toy Story 3', fon
este no es guau, pero es básico good: http://www.sthda.com/english/wiki/be-awesome-in-ggplot2-a-practical-guide-to-be-highly-effective-r-software-and-data-visualization#ggplot-build-plots-piece-by-piece
http://sape.inf.usi.ch/quick-reference/ggplot2/geom
http://r-statistics.co/Complete-Ggplot2-Tutorial-Part2-Customizing-Theme-With-R-Code.html
https://emitanaka.org/workshopUTokyo2018/day1-session02-datavis.html#1
#plotly - interactive graphics
library(plotly)
g <- ggplot(iris,
aes(Sepal.Length, Sepal.Width, color=Species)) +
geom_point()
ggplotly(g)
#- Simple animation with plotly
g <- ggplot(vargas.wheat1.traits,
aes(NGS, yield, frame=year)) +
geom_point(aes(color=gen)) +
geom_smooth(method="lm")
ggplotly(g)
#- GOOOOD
#- https://www.r-bloggers.com/visualizing-the-relationship-between-multiple-variables/
#- https://psu-psychology.github.io/r-bootcamp-2018/talks/ggplot2_tutorial_vallorani.html
library(GGally)
ggpairs(iris)
ggpairs(iris %>% select(1:4) %>% na.omit(), progress=FALSE, lower = list(combo = wrap("facethist", bins=6)))
si, puedes hacer al go asi como ejemplo, hacer todos los histogramas
# Looking at histograms for all variables ggplot option
ggplot(df %>% select(starts_with("proportion"), age) %>% # selecting non-binary variables
gather(), aes(value)) + # grouping for visualization
geom_histogram(bins = 5) +
facet_wrap(~key, scales = "free_x") # free_x allows for differing x-axes
Si pueed hacer un ejemplo con geom_smooth: It’s sometimes useful to map aesthetics to constants. For example, if you want to display multiple layers with varying parameters, you can “name” each layer:
ggplot(mpg, aes(displ, hwy)) +
geom_point() +
geom_smooth(aes(colour = "loess"), method = "loess", se = FALSE) +
geom_smooth(aes(colour = "lm"), method = "lm", se = FALSE) +
labs(colour = "Method")
Que aes tiene cada geom: https://www.yihanwu.ca/post/geoms-and-aesthetic-parameters/ GOO
Haz esto: https://drsimonj.svbtle.com/plotting-background-data-for-groups-with-ggplot2
GGVis (no veo la ventaja)
#-- GG vis
library(ggvis)
cc <- mtcars
mtcars %>% ggvis(~disp, ~mpg) %>% layer_points()
mtcars %>% ggvis(~wt, ~mpg, fill := "blue") %>% layer_points()
# Change the code below draw smooths instead of points
mtcars %>% ggvis(~wt, ~mpg) %>% layer_smooths()
# Change the code below to make a graph containing both points and a smoothed summary line
mtcars %>% ggvis(~wt, ~mpg) %>% layer_points() %>% layer_smooths()
El asistente Asistente para definir el tema en ggplot
Hace nada Pedro me comentó que existía un addin para ggplot que facilitaba mucho mucho la tarea de mejorar el aspecto estético de los gráficos (el tema del gráfico). No es que facilite, es que es una caña!!! y, como no podía ser de otra forma, aquí tenéis una introducción. Ahhh, se me olvidaba, ¡gracias Pedro!
Lo primero, vamos a instalar el paquete. Lo podemos instalar desde Github o desde el CRAN. Una vez instalado, lo cargamos.
Este paquete lo que nos facilita es la edición del tema. Para ello, una vez cargado el paquete, seleccionamos el código del gráfico que queremos “customizar” el tema y, a continuación, del menú Addins seleccionamos el Addin ggplot Theme Assistant.
Aquí tenéis el ejemplo que ha preparado el autor de este paquete y que podéis encontrar https://github.com/calligross/ggthemeassist
devtools::install_github(“calligross/ggthemeassist”)
parece que tb hay otro parecido: https://dreamrs.github.io/esquisse/index.html
https://twitter.com/WeAreRLadies/status/1139591763432222723
@dataandme: 👇 great for understanding ggplot2How’s it made (w/ code)…Anatomy of gghighlight" ✍️ @yutannihilat_en https://buff.ly/2MIPzyf
GUi para hacer ggplot facil https://github.com/dreamRs/esquisse
https://drsimonj.svbtle.com/label-line-ends-in-time-series-with-ggplot2
mas graficosinteractivos: https://cran.r-project.org/web/packages/ggiraphExtra/vignettes/introduction.html
gallery html: http://gallery.htmlwidgets.org/
Recuerda que aquí usan gapminder: http://r-statistics.co/ggplot2-Tutorial-With-R.html y tb aquí https://swcarpentry.github.io/r-novice-gapminder-es/08-plot-ggplot2/index.html
In many situations, you want to separate your data into groups, but render them in the same way. In other words, you want to be able to distinguish individual subjects, but not identify them. This is common in longitudinal studies with many subjects, where the plots are often descriptively called spaghetti plots. For example, the following plot shows the growth trajectory for each boy (each Subject):
library(gapminder)
df <- gapminder %>% filter(continent == "Europe")
ggplot(df, aes(year, lifeExp, group = country)) +
geom_point() +
geom_line()
If a group isn’t defined by a single variable, but instead by a combination of multiple variables, use interaction() to combine them, e.g. aes(group = interaction(school_id, student_id))
Sometimes we want to plot summaries that use different levels of aggregation: one layer might display individuals, while another displays an overall summary. Building on the previous example, suppose we want to add a single smooth line, showing the overall trend for all boys. If we use the same grouping in both layers, we get one smooth per boy:
ggplot(df, aes(year, lifeExp, group = country)) +
geom_line() +
geom_smooth(method = "lm", se = FALSE)
en llugar de eso:Instead of setting the grouping aesthetic in ggplot(), where it will apply to all layers, we set it in geom_line() so it applies only to the lines. There are no discrete variables in the plot so the default grouping variable will be a constant and we get one smooth:
ggplot(df, aes(year, lifeExp)) +
geom_line(aes(group = country)) +
geom_smooth(method = "lm", se = FALSE, size = 2)
ggplot(df, aes(as.character(year), lifeExp)) +
geom_boxplot()
There is one discrete variable in this plot, Occassion, so we get one boxplot for each unique x value. Now we want to overlay lines that connect each individual boy.
ggplot(df, aes(as.character(year), lifeExp)) +
geom_boxplot() +
geom_line(colour = "#3366FF", alpha = 0.5)
To get the plot we want, we need to override the grouping to say we want one line per boy:
ggplot(df, aes(as.character(year), lifeExp)) +
geom_boxplot() +
geom_line(aes(group = country), colour = "#3366FF", alpha = 0.5)
un tutorial antiguo q yop tenia
# Voy a seguir el ggplot tutorial
#==========================================
library(tidyverse)
library(gapminder)
library(plotly)
df <- gapminder %>% mutate(fyear = as.factor(year))
df_es <- df %>% filter(country == "Spain")
df_eu <- df %>% filter(continent == "Europe")
p <- ggplot()
p <- ggplot(df_es, aes(year, lifeExp))
p + geom_point(colour = "red") + geom_line() + scale_y_continuous(limits = c(0, 80))
p + geom_point(colour = "red") + geom_line() + scale_y_log10()
## piping data to ggplot
df_es %>% ggplot(aes(year, lifeExp)) + geom_point(colour = "red")
#- donde esta ESp en Europa
p <- df %>% filter(continent == "Europe") %>%
ggplot(aes(year, lifeExp)) +
geom_point(colour = "grey75") +
geom_point(data = df_es, colour = "blue") +
scale_y_continuous(limits=c(60,85))
ggplotly(p)
#- mio
p <- df %>% filter(continent == "Europe") %>%
ggplot(aes(year, lifeExp)) +
geom_point(data = df_eu, aes(colour = country)) +
geom_point(data = df_es, colour = "blue") +
scale_y_continuous(limits=c(60,85))
p <- df %>% filter(continent == "Europe") %>%
ggplot(aes(as.factor(year), lifeExp)) +
geom_boxplot() +
geom_point(data = df_es, colour="blue") +
scale_y_continuous(limits=c(60,85))
p <- df %>% filter(continent == "Europe") %>%
ggplot(aes(fyear, lifeExp)) +
geom_boxplot() +
geom_point(data = df_es, colour="blue") +
scale_y_continuous(limits=c(60,85)) +
scale_x_discrete(breaks = seq(1960, 2010, 10)) #- no me chuta
#- graficos de lineas
p <- df %>% filter(continent == "Europe") %>%
ggplot(aes(year, lifeExp, group = country)) +
geom_line(colour = "grey80") +
geom_line(data = df_es, colour="blue") +
scale_y_continuous(limits=c(0, 85))
presidential <- subset(presidential, start > economics$date[1])
ggplot(economics) +
geom_rect(
aes(xmin = start, xmax = end, fill = party),
ymin = -Inf, ymax = Inf, alpha = 0.2,
data = presidential
) +
geom_vline(
aes(xintercept = as.numeric(start)),
data = presidential,
colour = "grey50", alpha = 0.5
) +
geom_text(
aes(x = start, y = 2500, label = name),
data = presidential,
size = 3, vjust = 0, hjust = 0, nudge_x = 50
) +
geom_line(aes(date, unemploy)) +
scale_fill_manual(values = c("blue", "red")) +
xlab("date") +
ylab("unemployment")
yrng <- range(economics$unemploy)
xrng <- range(economics$date)
caption <- paste(strwrap("Unemployment rates in the US have
varied a lot over the years", 40), collapse = "\n")
ggplot(economics, aes(date, unemploy)) +
geom_line() +
geom_text(
aes(x, y, label = caption),
data = data.frame(x = xrng[1], y = yrng[2], caption = caption),
hjust = 0, vjust = 1, size = 4
)
This code works, and generates the desired plot, but it is very cumbersome. It would be annoying to have to do this every time you want to add a single annotation, so ggplot2 includes the annotate() helper function which creates the data frame for you:
ggplot(economics, aes(date, unemploy)) +
geom_line() +
annotate(
geom = "text", x = xrng[1], y = yrng[2],
label = caption, hjust = 0, vjust = 1, size = 4
)
The convenience of the annotate() function comes in handy in other situations. For example, a common form of annotation is to highlight a subset of points by drawing larger points in a different colour underneath the main data set. To highlight vehicles manufactured by Subaru you could use this to create the basic plot:
p <- ggplot(mpg, aes(displ, hwy)) +
geom_point(
data = filter(mpg, manufacturer == "subaru"),
colour = "orange",
size = 3
) +
geom_point()
The problem with this is that the highlighted category would not be labelled. This is easily rectified using annotate()
p +
annotate(geom = "point", x = 5.5, y = 40, colour = "orange", size = 3) +
annotate(geom = "point", x = 5.5, y = 40) +
annotate(geom = "text", x = 5.6, y = 40, label = "subaru", hjust = "left")
p +
annotate(
geom = "curve", x = 4, y = 35, xend = 2.65, yend = 27,
curvature = .3, arrow = arrow(length = unit(2, "mm"))
) +
annotate(geom = "text", x = 4.1, y = 35, label = "subaru", hjust = "left")
ggplot(mpg, aes(displ, hwy)) +
geom_point() +
ggforce::geom_mark_ellipse(aes(label = cyl, group = cyl))
ggplot(iris, aes(Sepal.Length, Petal.Length)) +
geom_point(aes(color = Species)) +
ggforce::geom_mark_ellipse(aes(label = Species, group = Species))
A third approach to direct labelling is provided in the gghighlight package by Hiroaki Yutani https://github.com/yutannihilation/gghighlight. In many situations is useful for highlighting points or lines (or indeed a variety of different geoms) within a plot, particularly for longitudinal data:
df <- gapminder %>% filter(continent == "Europe")
ggplot(df, aes(year, lifeExp, group = country)) +
geom_line() +
geom_point() +
gghighlight::gghighlight(country %in% c("Spain", "Portugal"))
A variation on this theme arises when you want each facet of a plot to display data from a single group, with the complete data set plotted unobtrusively in each panel to aid visual comparison. The gghighlight package is particularly useful in this context:
ggplot(iris, aes(Sepal.Length, Petal.Length, color = as.factor(Species))) +
geom_point() +
gghighlight::gghighlight() +
facet_wrap(vars(Species))
With base graphics, you can work with almost any data structure you’d like, providing you can write the code to work with it. For example, you data could be in a list or a data frame. Or maybe it’s scattered across multiple objects. ggplot2, on the other hand, requires you to think carefully about the data structure and then write one (possibly long) line of code. So, with base plotting you’ll tend to spend lots of time writing plotting code. With ggplot2 you’ll tend to spend time thinking beforehand, and then quickly write the code. ggplot() works with format data or data with each aesthetic or facet variable in its own column4.
https://stackoverflow.com/questions/tagged/ggplot2
ggplot2 template
ggplot(data = ) +
stat =
https://emitanaka.org/workshopUTokyo2018/day1-session02-datavis.html#6 Every ggplot object has:
Data
Aesthesitc mapping
Layer(s)
Purpose of a layer is to display:
the raw data,
a statistical summary, or
additional metadata such as context, annotations, and references.
Every layer has:
geom - the geometric object to use display the data, and stat - statistical transformation to use on the data for this layer.
data and mapping (aesthestics) which is usually inherited from ggplot() object.
position - position in the coordinate system.
p <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) p + geom_point() # blank + geom layer
which is a short-hand for:
p + layer(geom=“point”, stat=“identity”, position=“identity”)
geom Description geom_abline Reference lines: horizontal, vertical, and diagonal geom_bar Bar charts geom_bin2d Heatmap of 2d bin counts geom_blank Draw nothing geom_boxplot A box and whiskers plot (in the style of Tukey) geom_contour 2d contours of a 3d surface geom_count Count overlapping points geom_density Smoothed density estimates geom_density_2d Contours of a 2d density estimate geom_dotplot Dot plot geom_errorbarh Horizontal error bars geom_hex Hexagonal heatmap of 2d bin counts geom_freqpoly Histograms and frequency polygons geom_jitter Jittered points geom_crossbar Vertical intervals: lines, crossbars & errorbars geom_map Polygons from a reference map geom_path Connect observations geom_point Points geom_polygon Polygons geom_qq_line A quantile-quantile plot geom_quantile Quantile regression geom_ribbon Ribbons and area plots geom_rug Rug plots in the margins geom_segment Line segments and curves geom_smooth Smoothed conditional means geom_spoke Line segments parameterised by location, direction and distance geom_label Text geom_raster Rectangles geom_violin Violin plot
stat Description stat_count Bar charts stat_bin_2d Heatmap of 2d bin counts stat_boxplot A box and whiskers plot (in the style of Tukey) stat_contour 2d contours of a 3d surface stat_sum Count overlapping points stat_density Smoothed density estimates stat_density_2d Contours of a 2d density estimate stat_bin_hex Hexagonal heatmap of 2d bin counts stat_bin Histograms and frequency polygons stat_qq_line A quantile-quantile plot stat_quantile Quantile regression stat_smooth Smoothed conditional means stat_spoke Line segments parameterised by location, direction and distance stat_ydensity Violin plot stat_sf Visualise sf objects stat_ecdf Compute empirical cumulative distribution stat_ellipse Compute normal confidence ellipses stat_function Compute function for each x value stat_identity Leave data as is stat_sf_coordinates Extract coordinates from ‘sf’ objects stat_summary_bin Summarise y values at unique/binned x stat_summary_2d Bin and summarise in 2d (rectangle & hexagons) stat_unique Remove duplicates
Coordinate system
p2 <- ggplot(maize, aes(1, Count, fill=Type)) + guides(fill=FALSE) + theme_void()
p + geom_bar()
p + geom_bar() + coord_polar(theta=“y”)
Labels with geom_label
g <- ggplot(barley, aes(T4, height)) + geom_point(size=4, aes(color=factor(year))) + guides(color=FALSE) + xlab(“Avg temp (Celsius) in the 4-th period”) + ylab(“Height”) g + geom_label(data=maxh_df, size=4, aes(T4, height, label=year))
Nudge labels + geom_text
g + geom_text( data=maxh_df, size=4, nudge_y=10, aes(T4, height, label=year))
ggrepel
library(ggrepel) g + geom_label_repel( data=maxh_df, size=4, aes(T4, height, label=year))
By default, ggplot() assumes a Cartesian coordinate system (coord_cartesian). Here, we use coord_fixed() to define a Cartesian coordinate system with a fixed axis ratio. In this case, the ratio = 6/100 argument creates a square plot. coord_fixed(ratio = 6/100)
Tienes que entender porque son equivalentes. Busca la ayuda de la función y verás que el primer argumento de la función es data, así que si, como ocurre en la segunda expresión, no ponemos el nombre del argumento de la función, R tomará iris como el valor del primer argumento. Parece un trabalenguas pero es importante↩
Si alguno de vosotros me pregunta por la verdad adoptaré semblante hierático y sólo diré lo siguiente: geom_point() is a short-hand for layer(geom = “point”, stat = “identity”, position = “identity”) ó apelaré a la canción de Albert Pla, según me de.↩
En aes() no sólo puedes poner variables, sino transformaciones de ellas, por ejemplo aes(x = v1 ^ 2, y = v1 / v2). También se pueden mappear variables con constantes aes(x = 1, colour = “loquesea”)↩
En este caso sí quiero que me preguntéis por este detalle. Es algo que ya deberías saber/intuir pero …↩
Bueno la tercera expresión si correrá pero sólo mostrará los puntos, no las lineas.↩
O marcar/anotar los lirios 2 lirios más grandes o el lirio mediano. ¿Lo hacéis?↩